package javango.contrib.servlet;

import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javango.api.Settings;
import javango.api.Url;
import javango.core.SubappUrl;
import javango.spi.JavangoModule;

/**
 * Create injector from settings and optional list of other modules. Refactrored
 * out of Servlet class so that unit test can reuse it.
 */
public class InjectorSupport {

    public static Injector createInjector(final Settings settings, Module ...modules)  
            throws InstantiationException, IllegalAccessException {
        List<Module> moduleList = new ArrayList<Module>();
        
        // add all modules provided by javango submodules
        for (JavangoModule m : settings.getJavangoModules()) {
            if (m.getModule() != null) {
                moduleList.add(m.getModule());
            }
        }
        
        // add all modules provided by user in their Settings class
        if (settings.getModuleClasses() != null) {
            for (Class<? extends Module> m : settings.getModuleClasses()) {
                moduleList.add(m.newInstance());
            }
        }
        
        // add all explicitelly passed modules:
        moduleList.addAll(Arrays.asList(modules));

        // bind Settings.class to settings instance
        moduleList.add(new Module() {
            public void configure(Binder binder) {
                binder.bind(Settings.class).toInstance(settings);
            }
        });
        
        // create ultimate injector!
        Injector injector = Guice.createInjector(moduleList);
        
        // pass injector to javango submodules
        for (JavangoModule m : settings.getJavangoModules()) {
            m.init(injector);
        }
        
        // perform field injection on SubappUrl instances:
        for (Url u : settings.getUrls().getUrlPatterns()) {
            if (u instanceof SubappUrl) {
                injector.injectMembers(u);
            }
        }
        
        return injector;
	}
    
}
